﻿using System;
using SCG = System.Collections.Generic;

using Nemerle.Assertions;
using Nemerle.Utility;

using GASS.OpenCL;
using GASS.OpenCL.OpenCLDriver;

namespace Nemerle.OpenCL {

    public sealed class MemoryMap : IDisposable {

        internal this(command_queue : CommandQueue, memory : Memory, ptr : IntPtr, row_pitch : long, slice_pitch : long, map_evt : Event = null) {
            this.command_queue = command_queue;
            this.memory = memory;
            this.ptr = ptr;
            this.image_row_pitch = row_pitch;
            this.image_slice_pitch = slice_pitch;
            this.map_evt = map_evt;
            this.unmap_evt = null;
        }

        [Accessor] memory : Memory;

        [Accessor] command_queue : CommandQueue;

        [Accessor] ptr : IntPtr;

        [Accessor] image_row_pitch : long;

        [Accessor] image_slice_pitch : long;

        map_evt : Event;

        public IsMapped : bool {
            get { null == map_evt || map_evt.IsCompleted }
        }

        public WaitUntilMapped() : void {
            when(null != map_evt)
                map_evt.WaitOne();
        }

        mutable unmap_evt : Event; 

        public BeginUnmap(params deps : array[Event]) : Event {
            when(null == unmap_evt) {
                def (deps_len, deps) = Event.ConvertEventList(deps);
                mutable event_id;
                CheckError(clEnqueueUnmapMemObject(command_queue.Id, memory.Id, ptr, deps_len, deps, ref event_id));
                unmap_evt = Event(command_queue, event_id);
            }
            unmap_evt
        }

        public Dispose() : void {
            using(evt = BeginUnmap())
                evt.WaitOne();
        }

    }

}